#include "stdafx.h"
#include "YProactorTokenOnSend.h"
#include "ITcpSession.h"
#include "ITcpSessionCallback.h"
#include "YMessageBlock.h"

namespace ysimple_network
{
	YProactorTokenOnSend::YProactorTokenOnSend(void)
		: m_pCallback(nullptr)
		, m_availableWSACount(0)
		, m_pMessageBlock(nullptr)
		, m_pSession(nullptr)
	{
	}


	YProactorTokenOnSend::~YProactorTokenOnSend(void)
	{
	}

	void YProactorTokenOnSend::beginInit( YMessageBlock& messageBlock, ISendCallback& callback, ITCPSession& session )
	{
		resetOverlapped();

		m_pCallback = &callback;
		m_availableWSACount = 0;
		m_pMessageBlock = &messageBlock;
		m_pSession = &session;
		m_pSession->addRef();

		const size_t PER_SEND_SIZE = 4*1024;
		size_t sendSize = 0;
		messageBlock.foreach([&](PACKETBLOCK_SPTR& packet){

			if (m_availableWSACount >= _countof(m_wsabuf))
				return false;
			size_t availableLen = __min(sendSize +  packet->uncompletedLength(), PER_SEND_SIZE) - sendSize;			
			if (availableLen == 0)
				return false;
			
			m_wsabuf[m_availableWSACount].buf = packet->getrd();
			m_wsabuf[m_availableWSACount].len = availableLen;

			sendSize += availableLen;

			++m_availableWSACount;
			return true;
		});
		
		assert(sendSize > 0);
	}

	bool YProactorTokenOnSend::onCompleted( bool completionStatus, LONG_PTR completionKey, DWORD dwBytesTransfered )
	{
		if (completionStatus == false || dwBytesTransfered == 0)
		{
			m_pSession->disconnect();
		}
		else
		{
			m_pCallback->onSent(*m_pSession, completionStatus, dwBytesTransfered);
			SCOPED_LOCK(m_pMessageBlock->m_criticalSection);
			if (m_pMessageBlock->complete(dwBytesTransfered) == false)
			{
				m_pSession->resend(*m_pCallback);
			}
		}
		
		m_pSession->release();
		return true;
	}

	WSABUF* YProactorTokenOnSend::getWSABuf()
	{
		return m_wsabuf;
	}

	DWORD YProactorTokenOnSend::getWSABufCount()
	{
		return m_availableWSACount;
	}

	void YProactorTokenOnSend::endInit( bool success )
	{
		if (success == false)
		{
			m_pSession->release();
		}
	}

}

